//
// Created by twetec on 25-6-21.
//

#include <network_prober/database/file_db_holder.h>


namespace network_prober::database
{
enum class ProbeTaskResultTableColIdx : std::uint8_t
{
    id = 0,
    uuid,
    delay,
    packetLossRate,
    probeTime
};

void FileDBHolder::init()
{
    _initProbeTaskResultTable();    // 初始化观测任务结果表
}

void FileDBHolder::_initProbeTaskResultTable()
{
    // 建立数据库连接，初始化数据表
    duckdb_connection conn;

    // 连接数据库 conn
    duckdb_state ret = duckdb_connect(m_db, &conn);
    if (ret == DuckDBError) {
        duckdb_disconnect(&conn);
        duckdb_close(&m_db);
        throw std::runtime_error("文件数据库连接失败..");
    }

    SPDLOG_INFO("为 t_probe_task_result 表重置自增主键序列...");

    // 查询结果
    duckdb_result queryResult;

    SPDLOG_INFO("为 t_probe_task_result 表创建自增主键序列");

    std::string createPrimaryKeySequenceSQL("CREATE SEQUENCE IF NOT EXISTS seq_probe_task_result_id START 1;");
    ret = duckdb_query(conn, createPrimaryKeySequenceSQL.c_str(), &queryResult);
    if (ret == DuckDBError) {
        std::stringstream ss;
        ss << "t_probe_task_result 表 自增主键序列 创建失败: " << duckdb_result_error(&queryResult);
        duckdb_destroy_result(&queryResult);
        duckdb_disconnect(&conn);
        duckdb_close(&m_db);
        throw std::runtime_error(ss.str());
    }

    duckdb_destroy_result(&queryResult);

    // 执行SQL,创建表
    SPDLOG_INFO("初始化 t_probe_task_result 表..");

    std::stringstream createTableSQL;
    createTableSQL << "CREATE TABLE IF NOT EXISTS t_probe_task_result";
    createTableSQL << "(";
    createTableSQL << "id INTEGER PRIMARY KEY DEFAULT NEXTVAL('seq_probe_task_result_id'),";
    createTableSQL << "uuid VARCHAR(255)" << ",";
    createTableSQL << "delay HUGEINT" << ",";
    createTableSQL << "packetLossRate INTEGER" << ",";
    createTableSQL << "probeTime INTEGER";
    createTableSQL << ");";

    ret = duckdb_query(conn, createTableSQL.str().c_str(), &queryResult);
    if (ret == DuckDBError) {
        std::stringstream ss;
        ss << "t_probe_task_result 表创建失败: " << duckdb_result_error(&queryResult);
        duckdb_destroy_result(&queryResult);
        duckdb_disconnect(&conn);
        duckdb_close(&m_db);
        throw std::runtime_error(ss.str());
    }

    duckdb_destroy_result(&queryResult);
    duckdb_disconnect(&conn);

    SPDLOG_INFO("t_probe_task_result 表初始化完成..");
}

void FileDBHolder::batchInsertProbeTaskResults(std::span<ProbeTaskResultModel> probeTaskResults)
{
    // 建立数据库连接，初始化数据表
    duckdb_connection conn;

    // 连接数据库 conn
    duckdb_state ret = duckdb_connect(m_db, &conn);
    if (ret == DuckDBError) {
        duckdb_disconnect(&conn);
        duckdb_close(&m_db);
        throw std::runtime_error("文件数据库连接失败..");
    }

    // 执行SQL,创建表
    SPDLOG_INFO("向 t_probe_task_result 表 批量插入数据...");

    // duckdb追加器
    duckdb_appender appender;

    // 创建追加器
    if (duckdb_appender_create(conn, nullptr, "t_probe_task_result", &appender) == DuckDBError) {
        duckdb_disconnect(&conn);
        duckdb_close(&m_db);
        throw std::runtime_error("duckdb追加器创建失败..");
    }

    // 观测任务数量
    std::size_t probeTaskResultsSize = probeTaskResults.size();
    // 获取一批主键值
    std::int64_t* idSeqValues = static_cast<std::int64_t*>(malloc(probeTaskResultsSize * sizeof(int64_t)));

    // 查询结果
    duckdb_result idSeqQueryResult;

    // idSeqQuerySQL
    std::stringstream idSeqQuerySQL;
    idSeqQuerySQL << "SELECT nextval('seq_probe_task_result_id') FROM generate_series(" << probeTaskResultsSize << ");";
    // 查询主键
    duckdb_query(conn, idSeqQuerySQL.str().c_str(), &idSeqQueryResult);
    // 读取主键
    for (std::size_t i = 0; i < probeTaskResultsSize; i++) {
        idSeqValues[i] = duckdb_value_int64(&idSeqQueryResult, 0, i);
    }

    // 销毁查询
    duckdb_destroy_result(&idSeqQueryResult);

    // 遍历追加
    std::size_t flushRowCount = 0;

    // 遍历行，开始追加
    std::size_t index = 0;
    for (auto it = probeTaskResults.begin(); it != probeTaskResults.end(); it++) {
        // 开始行
        duckdb_appender_begin_row(appender);

        // 计算当前probeTask索引值
        index = std::distance(probeTaskResults.begin(), it);
        duckdb_append_int64(appender, idSeqValues[index]);  // 主键

        duckdb_append_varchar(appender, it->uuid.c_str());
        duckdb_append_int64(appender, it->delay);
        duckdb_append_int8(appender, it->packetLossRate);
        duckdb_append_int64(appender, it->probeTime);

        // SPDLOG_INFO("id: {} | uuid: {} | packetLossRate: {} | probeTime: {}", idSeqValues[index], it->uuid.c_str(), it->packetLossRate, it->probeTime);

        // 结束行
        duckdb_appender_end_row(appender);

        // 每1000条刷新一次
        if (++flushRowCount % 1000 == 0) duckdb_appender_flush(appender);
    }

    // 释放主键序列
    free(idSeqValues);

    // 将缓存刷进数据库
    if (duckdb_appender_close(appender) == DuckDBError) {
        // 获取错误数据
        duckdb_error_data errorData = duckdb_appender_error_data(appender);
        // 错误日志
        SPDLOG_INFO("duckdb追加器插入数据失败: 类型-{},信息:{}", static_cast<std::uint8_t>(duckdb_error_data_error_type(errorData)), duckdb_error_data_message(errorData));
        // 销毁追加器。将所有数据写入表
        duckdb_destroy_error_data(&errorData);
        duckdb_appender_destroy(&appender);
        duckdb_disconnect(&conn);
        // 结束执行
        return;
    }

    // 销毁追加器。将所有数据写入表
    duckdb_appender_destroy(&appender);
    duckdb_disconnect(&conn);

    SPDLOG_INFO("t_probe_task_result 表 批量插入成功: {}", flushRowCount);
}

void FileDBHolder::batchRemoveProbeTaskResultsByTargetUUID(std::string_view uuid)
{
    // 建立数据库连接，初始化数据表
    duckdb_connection conn;

    // 连接数据库 conn
    duckdb_state ret = duckdb_connect(m_db, &conn);
    if (ret == DuckDBError) {
        duckdb_disconnect(&conn);
        duckdb_close(&m_db);
        throw std::runtime_error("文件数据库连接失败..");
    }

    // 删除所有记录
    std::stringstream removeSQL;
    removeSQL << "DELETE FROM t_probe_task_result WHERE uuid='" << uuid << "';";

    std::string sql = removeSQL.str();

    SPDLOG_INFO("批量删除指定观测目标的观测记录：{}", sql);

    // 查询结果
    duckdb_result queryResult;

    // 执行查询
    ret = duckdb_query(conn, sql.c_str(), &queryResult);
    if (ret == DuckDBError) {
        std::stringstream ss;
        ss << "t_probe_task_result 表 删除uuid的观测设备的观测记录 失败: " << duckdb_result_error(&queryResult);
        duckdb_destroy_result(&queryResult);
        duckdb_disconnect(&conn);
        duckdb_close(&m_db);
        throw std::runtime_error(ss.str());
    }

    duckdb_destroy_result(&queryResult);
    duckdb_disconnect(&conn);

    SPDLOG_INFO("t_probe_task_result 表 删除观测设备的观测记录完成..");
}

void FileDBHolder::batchRemoveAllProbeTaskResults()
{
    // 建立数据库连接，初始化数据表
    duckdb_connection conn;

    // 连接数据库 conn
    duckdb_state ret = duckdb_connect(m_db, &conn);
    if (ret == DuckDBError) {
        duckdb_disconnect(&conn);
        duckdb_close(&m_db);
        throw std::runtime_error("内存数据库连接失败..");
    }

    // 删除所有记录
    std::string removeAllSQL("TRUNCATE TABLE t_probe_task_result");

    // 查询结果
    duckdb_result queryResult;

    // 执行查询
    ret = duckdb_query(conn, removeAllSQL.c_str(), &queryResult);
    if (ret == DuckDBError) {
        std::stringstream ss;
        ss << "t_probe_task_result 表 删除所有记录 失败: " << duckdb_result_error(&queryResult);
        duckdb_destroy_result(&queryResult);
        duckdb_disconnect(&conn);
        duckdb_close(&m_db);
        throw std::runtime_error(ss.str());
    }

    duckdb_destroy_result(&queryResult);
    duckdb_disconnect(&conn);

    SPDLOG_INFO("t_probe_task_result 表 删除所有记录完成..");
}

std::vector<ProbeTaskResultModel> FileDBHolder::getProbeTaskResultsByUUIDsAndStartEndTime(const std::vector<std::string>& uuids, std::string_view startTime, std::string_view endTime)
{
    // 建立数据库连接，初始化数据表
    duckdb_connection conn;

    // 连接数据库 conn
    duckdb_state ret = duckdb_connect(m_db, &conn);
    if (ret == DuckDBError) {
        duckdb_disconnect(&conn);
        duckdb_close(&m_db);
        throw std::runtime_error("文件数据库连接失败..");
    }

    // 查询结果
    duckdb_result queryResult;

    // 查询语句
    std::stringstream getSQL;
    getSQL << "SELECT * FROM t_probe_task_result WHERE ";
    getSQL << "(" << "probeTime BETWEEN " << startTime << " AND " << endTime << ")";
    getSQL << " AND ";
    getSQL << "uuid IN (";

    for(auto it = uuids.begin(); it != uuids.end(); it++) {
        getSQL << "'" << *it << "',";
    }

    std::string sql = getSQL.str();

    // 移除最后一个,
    sql.erase(sql.find_last_of(","), 1);
    // 追加一个;
    sql.append(");");

    SPDLOG_INFO(sql);

    // 执行查询
    ret = duckdb_query(conn, sql.c_str(), &queryResult);
    if (ret == DuckDBError) {
        std::stringstream ss;
        ss << "从 t_probe_task_result 表获取观测结果 失败: " << duckdb_result_error(&queryResult);
        duckdb_destroy_result(&queryResult);
        duckdb_disconnect(&conn);
        duckdb_close(&m_db);
        throw std::runtime_error(ss.str());
    }

    // 获取结果集的行数
    idx_t resultRowCount = duckdb_row_count(&queryResult);

    // 从查询结果中构建集合
    std::vector<ProbeTaskResultModel> probeTaskResults;
    probeTaskResults.reserve(resultRowCount);

    // 遍历结果集，组装成模型
    // 遍历行
    for (idx_t row = 0; row < resultRowCount; row++) {
        // 构建观测目标对象
        ProbeTaskResultModel probeTaskResult;

        // 获取每个单元格值
        probeTaskResult.id = duckdb_value_varchar(&queryResult, static_cast<idx_t>(ProbeTaskResultTableColIdx::id), row);
        probeTaskResult.uuid = duckdb_value_varchar(&queryResult, static_cast<idx_t>(ProbeTaskResultTableColIdx::uuid), row);
        probeTaskResult.delay = duckdb_value_int64(&queryResult, static_cast<idx_t>(ProbeTaskResultTableColIdx::delay), row);
        probeTaskResult.packetLossRate = duckdb_value_uint32(&queryResult, static_cast<idx_t>(ProbeTaskResultTableColIdx::packetLossRate), row);
        probeTaskResult.probeTime = duckdb_value_int64(&queryResult, static_cast<idx_t>(ProbeTaskResultTableColIdx::probeTime), row);

        // 归集模型数据
        probeTaskResults.push_back(std::move(probeTaskResult));
    }

    duckdb_destroy_result(&queryResult);
    duckdb_disconnect(&conn);

    SPDLOG_INFO("从 t_probe_task_result 表获取观测结果 成功..");

    return probeTaskResults;
}

FileDBHolder &FileDBHolder::getInstance()
{
    static FileDBHolder instance;
    return instance;
}

FileDBHolder::FileDBHolder()
{
    // 配置数据库
    duckdb_config config;

    // 创建配置项
    duckdb_state ret = duckdb_create_config(&config);
    if (ret == DuckDBError) {
        duckdb_destroy_config(&config);
        duckdb_close(&m_db);
        throw std::runtime_error("文件数据库配置项创建失败..");
    }

    // 设定配置项
    duckdb_set_config(config, "access_mode", "AUTOMATIC"); // 数据库的访问模式（AUTOMATIC（自动）、READ_ONLY（只读）或 READ_WRITE（读写）） 默认：AUTOMATIC
    // duckdb_set_config(config, "threads", "4");  // 系统使用的总线程数 默认：CPU 核心数
    duckdb_set_config(config, "wal_autocheckpoint", "1GB");  // 自动触发检查点的 WAL 大小阈值 默认：16.0 MiB
    duckdb_set_config(config, "default_order", "DESC"); // 未指定时使用的排序类型 默认：ASC

    // 连接数据库文件 (用进程独占文件)
    ret = duckdb_open_ext(DB_FILE_PATH, &m_db, config, nullptr);
    if (ret == DuckDBError) {
        duckdb_destroy_config(&config);
        duckdb_close(&m_db);
        throw std::runtime_error("文件数据库打开失败...");
    }

    // 回收配置资源 （配置完配置项就无效了）
    duckdb_destroy_config(&config);
}

FileDBHolder::~FileDBHolder()
{
    duckdb_close(&m_db);
    SPDLOG_INFO("文件数据库holder释放完成..");
}


}
